package com.example.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.dto.AccountDto;
import com.example.entity.dto.StoreImageDto;
import com.example.mapper.AccountMapper;
import com.example.mapper.ImageStoreMapper;
import com.example.service.ImageService;
import com.example.utils.FlowUtils;
import io.minio.*;
import io.minio.errors.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

import static com.example.utils.Const.FORUM_IMAGE_COUNTER;

@Slf4j
@Service
public class ImageServiceImpl
        extends ServiceImpl<ImageStoreMapper, StoreImageDto>
        implements ImageService {


    //minio客户端
    @Resource
    private MinioClient minioClient;

    @Resource
    private AccountMapper accountMapper;

    //限流工具类
    @Resource
    private FlowUtils flowUtils;

    private final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");

    @Override
    public String uploadAvatar(MultipartFile file, int id) throws IOException {
        //生成随机的用户名
        //防止本地缓存和爬虫
        String imageName = UUID.randomUUID().toString().replace("-","");
        imageName = "/avatar/" + imageName;
        //构建minio存储对象
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket("graduation")
                .stream(file.getInputStream(),file.getSize(),-1)
                .object(imageName)
                .build();
        //存到minio客户端存到服务端
        try {
            minioClient.putObject(putObjectArgs);
            //删除旧的头像
            String avatar = accountMapper.selectById(id).getAvatar();
            this.deleteOldAvatar(avatar);
            //将新头像的URL同步到数据库
            if(accountMapper.update(null, Wrappers.<AccountDto>update()
                    .eq("id", id).set("avatar", imageName)) > 0){
                return imageName;
            }else {
                return null;
            }
        }catch (Exception e){
            log.warn("头像上传出现异常："+e.getMessage());
            return null;
        }
    }

    @Override
    public void fetchImageFromMinio(OutputStream stream, String imagePath) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket("graduation")
                .object(imagePath)
                .build();
        GetObjectResponse response = minioClient.getObject(getObjectArgs);
        //返回的response本身就是一个输出流
        IOUtils.copy(response,stream);
    }

    @Override
    public String uploadImage(MultipartFile file, int id) throws IOException {
        // 生成一个基于论坛图片计数器的唯一键值，用于限流
        String key = FORUM_IMAGE_COUNTER + id;
        // 检查给定的ID在1小时内是否超过了20次上传限制，如果是，则返回null
        if(!flowUtils.limitPeriodCounterCheck(key, 20, 3600))
            return null;

        // 使用UUID生成唯一的图片名称，并移除其中的"-"符号
        String imageName = UUID.randomUUID().toString().replace("-", "");
        Date date = new Date();
        // 设置图片存储路径，包括缓存目录、日期和随机生成的图片名
        imageName = "/cache/" + format.format(date) + "/" + imageName;

        // 构建上传参数对象，包括存储桶名称、图片流、文件大小和对象（图片）名称
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket("graduation")
                .stream(file.getInputStream(), file.getSize(), -1)
                .object(imageName)
                .build();

        //记录在数据库中，用户和图片上传的映射，方便后续的删除
        try {
            // 执行上传操作
            minioClient.putObject(args);
            // 如果图片信息保存成功，则返回图片名称；否则返回null
            if(this.save(new StoreImageDto(id, imageName, date))) {
                return imageName;
            } else {
                return null;
            }
        } catch (Exception e) {
            // 记录上传过程中出现的异常
            log.error("图片上传出现问题: "+ e.getMessage(), e);
            return null;
        }
    }


    //删除旧的头像
    private void deleteOldAvatar(String avatar) throws Exception {
        if(avatar == null || avatar.isEmpty()) return;
        RemoveObjectArgs remove = RemoveObjectArgs.builder()
                .bucket("study")
                .object(avatar)
                .build();
        minioClient.removeObject(remove);
    }

}
